package com.econ.powercloud.ems.service.biz;

import com.econ.powercloud.common.base.facade.enums.StatusType;
import com.econ.powercloud.common.base.facade.exception.CommonRuntimeException;
import com.econ.powercloud.common.base.facade.pojo.MsgResult;
import com.econ.powercloud.common.base.facade.util.JacksonUtil;
import com.econ.powercloud.ems.common.enums.ControlRecordStatusEnum;
import com.econ.powercloud.ems.common.enums.DitTypeEnum;
import com.econ.powercloud.ems.common.enums.ListingTypeEnum;
import com.econ.powercloud.ems.common.enums.RemoteType;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.dal.entity.*;
import com.econ.powercloud.ems.dal.entity.ext.IotEdgePlatformSyncMsg;
import com.econ.powercloud.ems.pojo.FlashDataVO;
import com.econ.powercloud.ems.pojo.QueryDataVO;
import com.econ.powercloud.ems.pojo.YkYtIssueConfirmVO;
import com.econ.powercloud.ems.pojo.requestVO.*;
import com.econ.powercloud.ems.rpc.IFeignPowerNodeConsoleClient;
import com.econ.powercloud.ems.service.common.QueryFlashDataCommonService;
import com.econ.powercloud.ems.service.dao.*;
import com.econ.powercloud.ems.util.NetUtils;
import com.econ.powercloud.powernode.gateway.base.utils.CurrentUserUtil;
import com.econ.powercloud.powernode.gateway.common.domain.UserDTO;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.Assert;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author : zjf
 * @Description : ems项目中遥控遥调下发service
 * @Date : 2021/10/14 9:48
 * @Modified by : zjf
 */
@Slf4j
@Service
public class EmsYkYtIssueService {

    @Autowired
    private EmsDeviceDAO emsDeviceDAO;
    @Autowired
    private EmsYkYtRecordDAO emsYkYtRecordDAO;
    @Autowired
    private IFeignPowerNodeConsoleClient iFeignPowerNodeConsoleClient;
    @Autowired
    private EmsControlRecordDAO emsControlRecordDAO;
    @Autowired
    private EmsControlRecordDetailDAO emsControlRecordDetailDAO;
    @Autowired
    private EmsYkYtIssueService emsYkYtIssueService;
    @Autowired
    private IotDeviceYkYtDitDAO iotDeviceYkYtDitDAO;
    @Autowired
    private EmsControlRecordLogDAO emsControlRecordLogDAO;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private IotProductYkYtDitDAO iotProductYkYtDitDAO;
    @Autowired
    private QueryFlashDataCommonService queryFlashDataCommonService;
    @Autowired
    private IotProductYcDAO iotProductYcDAO;
    @Autowired
    private IotProductYxDAO iotProductYxDAO;
    @Autowired
    private ExtIotNodeDAO extIotNodeDAO;
    @Autowired
    private EmsDeviceLockDAO emsDeviceLockDAO;
    @Autowired
    private IotMqttSyncMsgDAO iotMqttSyncMsgDAO;
    /**
     * 遥控遥调数据下发
     */
    @Transactional(rollbackFor = Exception.class)
    public MsgResult modifyYtData(EmsIssueRequestVO requestVO){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        RemoteType remoteType = RemoteType.fromCode(requestVO.getRemoteType());
        this.validateDeviceLock(Lists.newArrayList(emsDevice));
        this.dealYkYtIssue(emsDevice,remoteType,requestVO.getVal(),requestVO.getRemoteDit());
        return MsgResult.builder().status(StatusType.OK.getCode()).statusText(StatusType.OK.getStatusText()).data(true).build();
    }

    /**
     * 根据点号类型下发遥控遥调
     * @param requestVO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public MsgResult modifyDataByDitType(YkYtIssueRequestVO requestVO){
        EmsDevice emsDevice = emsDeviceDAO.selectByDeviceCode(requestVO.getDeviceCode());
        RemoteType remoteType = Objects.equals(DitTypeEnum.YT.getCode(),requestVO.getDitType())?RemoteType.YT
                :Objects.equals(DitTypeEnum.YK.getCode(),requestVO.getDitType())?RemoteType.YK:null;
        Assert.notNull(remoteType,"只有遥控遥调点号才能下发！");
        this.validateDeviceLock(Lists.newArrayList(emsDevice));
        this.dealYkYtIssue(emsDevice,remoteType,requestVO.getVal(),requestVO.getDit());
        return MsgResult.builder().status(StatusType.OK.getCode()).statusText(StatusType.OK.getStatusText()).data(true).build();
    }

    /**
     * 群控群调
     * @param list
     * @return
     */
    public boolean groupControl(List<YkYtIssueRequestVO> list,String clientIp) {
        list.stream().forEach(item -> Assert.isTrue(DitTypeEnum.isYkYt(item.getDitType()), "参数错误，只能是遥控/遥调"));
        //如果是遥调，校验是否超出额定范围
        List<EmsDevice> emsDeviceList = emsDeviceDAO.selectByDeviceCodes(list.stream().map(YkYtIssueRequestVO::getDeviceCode).distinct().collect(Collectors.toList()));
        this.validateDeviceLock(emsDeviceList);
        Map<String, EmsDevice> emsDeviceMap = emsDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, Function.identity(), (v1, v2) -> v1));
        List<IotDeviceYkYtDit> ytDits = iotDeviceYkYtDitDAO.selectByDeviceCodeAndDitAndRemoteType(
                emsDeviceList.stream().map(EmsDevice::getInitDeviceCode).collect(Collectors.toList()),
                list.stream().map(YkYtIssueRequestVO::getDit).collect(Collectors.toList()),
                RemoteType.YT.getCode());
        Map<String, IotDeviceYkYtDit> ytDitMap = ytDits.stream().collect(Collectors.toMap(item -> item.getDeviceCode() + SysConstant.SPOT + item.getDit(), Function.identity(), (o1, o2) -> o2));
        list.stream().filter(d-> DitTypeEnum.YT.getCode().equals(d.getDitType())).forEach(item -> {
            EmsDevice emsDevice = emsDeviceMap.get(item.getDeviceCode());
            IotDeviceYkYtDit iotDeviceYkYtDit = ytDitMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + item.getDit());
            if (iotDeviceYkYtDit.getRangeStart() != null && item.getVal() < iotDeviceYkYtDit.getRangeStart()) {
                throw new CommonRuntimeException(String.format("%s, %s, 设定值不能小于%s", emsDevice.getDeviceName(), iotDeviceYkYtDit.getDitName(), iotDeviceYkYtDit.getRangeStart()));
            }
            if (iotDeviceYkYtDit.getRangeEnd() != null && item.getVal() > iotDeviceYkYtDit.getRangeEnd()){
                throw new CommonRuntimeException(String.format("%s, %s, 设定值不能大于%s", emsDevice.getDeviceName(), iotDeviceYkYtDit.getDitName(), iotDeviceYkYtDit.getRangeEnd()));
            }
        });
        UserDTO userDTO = CurrentUserUtil.get();
        long now = System.currentTimeMillis();
        EmsControlRecord record = EmsControlRecord.builder()
                .status(ControlRecordStatusEnum.IN_PROGRESS.getCode()).gmtCreate(now).gmtModify(now)
                .createdBy(userDTO == null?null:userDTO.getId()).build();
        transactionTemplate.execute((TransactionStatus transactionStatus) -> {
            try{
                emsControlRecordDAO.save(record);
                List<EmsControlRecordDetail> detailList = JacksonUtil.convertToList(list, EmsControlRecordDetail.class);
                for (int i = 0 ; i < detailList.size(); i++) {
                    EmsControlRecordDetail item = detailList.get(i);
                    item.setInitDeviceCode(emsDeviceMap.get(item.getDeviceCode()).getInitDeviceCode());
                    item.setRecordId(record.getId());
                    item.setStepNum(i+1);
                    item.setStatus(ControlRecordStatusEnum.NOT_STARTED.getCode());
                    item.setClientIp(clientIp);
                    item.setGmtCreate(now);
                    item.setGmtModify(now);
                }
                emsControlRecordDetailDAO.saveBatch(detailList);
                //打印群控群调前端请求参数与后端存储的数据日志
                String log = String.format("群控群调->请求开始执行：前端请求参数：%s,后端群控群调记录详情为：%s",JacksonUtil.toJSONString(list),
                        JacksonUtil.toJSONString(detailList));
                emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(record.getId()).content(log).gmtCreate(new Date()).build());
                return true;
            }catch (Throwable e) {
                transactionStatus.setRollbackOnly();
                e.printStackTrace();
                throw new CommonRuntimeException(StatusType.DB_ERROR, "群控群调操作失败！");
            }
        });
        EmsControlRecordDetail first = emsControlRecordDetailDAO.selectByRecordIdOrderByStepId(record.getId());
        this.executeStep(first);
        return true;
    }

    /**
     * 获取遥测遥信点号对应的反馈与实时点号
     * @param list
     * @return
     */
    public List<YkYtIssueConfirmVO> getYkYtIssueConfirmData(List<YkYtIssueRequestVO> list){
        List<YkYtIssueRequestVO> ykList = Lists.newArrayList();
        List<YkYtIssueRequestVO> ytList = Lists.newArrayList();
        list.stream().forEach(item -> {
            Assert.isTrue(DitTypeEnum.isYkYt(item.getDitType()), "参数错误，只能是遥控/遥调");
            //对数据根据YKYT类型分为两个list，便于后续查询数据
            if(item.getDitType().equals(DitTypeEnum.YK.getCode())) {
                ykList.add(item);
            }else{
                ytList.add(item);
            }
        });
        List<YkYtIssueConfirmVO> ykYtIssueConfirmVOList = Lists.newArrayList();
        //获取设备有哪些
        List<EmsDevice> emsDeviceList = emsDeviceDAO.selectByDeviceCodes(list.stream().map(d->d.getDeviceCode()).collect(Collectors.toList()));
        List<String> productKeys = emsDeviceList.stream().map(d->d.getProductKey()).collect(Collectors.toList());
        //EMS设备map,key:deviceCode(EMS中的设备编号)
        Map<String, EmsDevice> emsDeviceMap = emsDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, Function.identity(), (v1, v2) -> v1));
        //获取对应的遥控遥调信息
        List<IotProductYkYtDit> productYkYtDitList = iotProductYkYtDitDAO.selectListByProductKeysAndDits(productKeys,
                list.stream().map(YkYtIssueRequestVO::getDit).collect(Collectors.toList()));
        //产品遥控遥调map,key: productKey + . + dit
        Map<String,IotProductYkYtDit> productYkYtDitMap = productYkYtDitList.stream().collect(Collectors.toMap(d->d.getProductKey() + SysConstant.SPOT + d.getDit(),d->d,(p1,p2)->p1));
        //定义需要查询的实时数据
        List<QueryDataVO> queryDataVOList = Lists.newArrayList();
        Map<String, IotEdgePlatformSyncMsg> msgMap = Maps.newHashMap();
        if(!ykList.isEmpty()) {
            //查询遥控点号最新数据
            List<String> ykDeviceCodeList = Lists.newArrayList();
            for (YkYtIssueRequestVO vo : ykList) {
                EmsDevice emsDevice = emsDeviceMap.get(vo.getDeviceCode());
                if(emsDevice!=null) {
                    ykDeviceCodeList.add(emsDevice.getInitDeviceCode());
                }
            }
            List<IotEdgePlatformSyncMsg> iotEdgePlatformSyncMsgs = iotMqttSyncMsgDAO.selectLastListByCondition(DitTypeEnum.YK.name(), ykDeviceCodeList, ykList.stream().map(YkYtIssueRequestVO::getDit).collect(Collectors.toList()));
            if(!iotEdgePlatformSyncMsgs.isEmpty()) {
                msgMap.putAll(iotEdgePlatformSyncMsgs.stream().collect(Collectors.toMap(d->d.getDeviceCode() + SysConstant.SPOT + d.getServiceCode(), d->d,(p1, p2)->p1)));
            }
        }
        if(!ytList.isEmpty()) {
            //查询遥调点号最新数据
            List<String> ytDeviceCodeList = Lists.newArrayList();
            for (YkYtIssueRequestVO vo : ytList) {
                EmsDevice emsDevice = emsDeviceMap.get(vo.getDeviceCode());
                if(emsDevice!=null) {
                    ytDeviceCodeList.add(emsDevice.getInitDeviceCode());
                }
            }
            List<IotEdgePlatformSyncMsg> iotEdgePlatformSyncMsgs = iotMqttSyncMsgDAO.selectLastListByCondition(DitTypeEnum.YT.name(), ytDeviceCodeList, ytList.stream().map(YkYtIssueRequestVO::getDit).collect(Collectors.toList()));
            if(!iotEdgePlatformSyncMsgs.isEmpty()) {
                msgMap.putAll(iotEdgePlatformSyncMsgs.stream().collect(Collectors.toMap(d->d.getDeviceCode() + SysConstant.SPOT + d.getServiceCode(), d->d,(p1, p2)->p1)));
            }
        }
        list.stream().forEach(d->{
            EmsDevice emsDevice = emsDeviceMap.get(d.getDeviceCode());
            Assert.notNull(emsDevice,"设备不存在！");
            IotEdgePlatformSyncMsg iotEdgePlatformSyncMsg = msgMap.get(emsDevice.getInitDeviceCode() + SysConstant.SPOT + d.getDit());
            IotProductYkYtDit iotProductYkYtDit = productYkYtDitMap.get(emsDevice.getProductKey() + SysConstant.SPOT + d.getDit());
            Assert.notNull(iotProductYkYtDit,"遥控遥调点号不存在！");
            YkYtIssueConfirmVO ykYtIssueConfirmVO = YkYtIssueConfirmVO.builder()
                    .deviceCode(d.getDeviceCode()).ditType(d.getDitType()).ykYtDit(d.getDit()).setVal(d.getVal()!=null?d.getVal():iotEdgePlatformSyncMsg!=null?Double.valueOf(iotEdgePlatformSyncMsg.getServiceValue()):null)
                    .deviceName(emsDevice.getDeviceName())
                    .feedBackPid(iotProductYkYtDit.getFeedBackDit() == null?null : emsDevice.getInitDeviceCode() + SysConstant.SPOT + iotProductYkYtDit.getFeedBackDit())
                    .actualPid(iotProductYkYtDit.getActualDit() == null?null : emsDevice.getInitDeviceCode() + SysConstant.SPOT + iotProductYkYtDit.getActualDit())
                    .build();
            ykYtIssueConfirmVOList.add(ykYtIssueConfirmVO);
            if(ykYtIssueConfirmVO.getFeedBackPid() != null){
                queryDataVOList.add(QueryDataVO.builder()
                        .pid(ykYtIssueConfirmVO.getFeedBackPid()).deviceCode(d.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(iotProductYkYtDit.getFeedBackDit()).build());
            }
            if(ykYtIssueConfirmVO.getActualPid() != null){
                queryDataVOList.add(QueryDataVO.builder()
                        .pid(ykYtIssueConfirmVO.getActualPid()).deviceCode(d.getDeviceCode()).initDeviceCode(emsDevice.getInitDeviceCode())
                        .dit(iotProductYkYtDit.getActualDit()).build());
            }
        });
        //查询实时值与反馈值的实时数据
        List<FlashDataVO> flashVOS = queryFlashDataCommonService.getFlashData(queryDataVOList);
        //获取需要查询的反馈值与实时值点号名称,key:productKey + . + dit,value:遥测遥信点号名称
        Map<String,String> ditNameMap = Maps.newHashMap();
        if(!CollectionUtils.isEmpty(queryDataVOList)){
            ditNameMap.putAll(iotProductYcDAO.selectListByProductKeysAndDits(productKeys,queryDataVOList.stream().map(d->d.getDit()).collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(d->d.getProductKey() + SysConstant.SPOT + d.getDit(), IotProductYc::getName,(p1, p2)->p1)));
        }
        if(!CollectionUtils.isEmpty(queryDataVOList)){
            ditNameMap.putAll(iotProductYxDAO.selectListByProductKeysAndDits(productKeys,queryDataVOList.stream().map(d->d.getDit()).collect(Collectors.toList()))
                    .stream().collect(Collectors.toMap(d->d.getProductKey() + SysConstant.SPOT + d.getDit(), IotProductYx::getName,(p1, p2)->p1)));
        }
        //实时数据map,key：pid(iot设备编号 + . + dit),value:实时值
        Map<String, String> flashDataMap = flashVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
        ykYtIssueConfirmVOList.stream().forEach(d->{
            EmsDevice emsDevice = emsDeviceMap.get(d.getDeviceCode());
            IotProductYkYtDit iotProductYkYtDit = productYkYtDitMap.get(emsDevice.getProductKey() + SysConstant.SPOT + d.getYkYtDit());
            d.setFeedBackVal(d.getFeedBackPid() == null?null : flashDataMap.get(d.getFeedBackPid()));
            d.setFeedBackPidName(d.getFeedBackPid() == null?null: ditNameMap.get(emsDevice.getProductKey() + SysConstant.SPOT + iotProductYkYtDit.getFeedBackDit()));
            d.setActualVal(d.getActualPid() == null?null : flashDataMap.get(d.getActualPid()));
            d.setActualPidName(d.getActualPid() == null?null: ditNameMap.get(emsDevice.getProductKey() + SysConstant.SPOT + iotProductYkYtDit.getActualDit()));
        });

        return ykYtIssueConfirmVOList;
    }

    /**
     * 执行步骤
     * @param recordDetail
     */
    public void executeStep(EmsControlRecordDetail recordDetail) {
        log.info("执行executeStep, recordDetailId: {}", recordDetail.getId());
        EmsControlRecord record = emsControlRecordDAO.getById(recordDetail.getRecordId());
        //流程是进行中状态，才可以执行步骤
        if (!record.getStatus().equals(ControlRecordStatusEnum.IN_PROGRESS.getCode())) {
            //主流程不是进行中状态,无需进行
            String log = String.format("群控群调->主记录流程不处于进行中,主记录数据：%s",JacksonUtil.toJSONString(record));
            emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(recordDetail.getRecordId()).content(log).gmtCreate(new Date()).build());
            return;
        }
        //当前步骤是未开始状态，才可以执行，防止重复执行
        if (!recordDetail.getStatus().equals(ControlRecordStatusEnum.NOT_STARTED.getCode())) {
            //当前步骤不处于未开始状态,无需进行
            String log = String.format("群控群调->某条记录详情流程不处于未开始状态,记录详情数据：%s",JacksonUtil.toJSONString(recordDetail));
            emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(recordDetail.getRecordId()).content(log).gmtCreate(new Date()).build());
            return;
        }
        //将当前步骤状态改为进行中
        recordDetail.setStatus(ControlRecordStatusEnum.IN_PROGRESS.getCode());
        long now = System.currentTimeMillis();
        recordDetail.setBeginTime(now);
        recordDetail.setGmtModify(now);
        emsControlRecordDetailDAO.updateById(recordDetail);
        Integer remoteType = null;
        if (recordDetail.getDitType().equals(DitTypeEnum.YK.getCode())) {
            remoteType = RemoteType.YK.getCode();
        } else if (recordDetail.getDitType().equals(DitTypeEnum.YT.getCode())) {
            remoteType = RemoteType.YT.getCode();
        }
        EmsIssueInitRequestVO requestVO = new EmsIssueInitRequestVO().setInitDeviceCode(recordDetail.getInitDeviceCode())
                .setRemoteType(remoteType).setRemoteDit(recordDetail.getDit()).setVal(Double.valueOf(recordDetail.getVal())).setDeviceCode(recordDetail.getDeviceCode());
        Integer msgId = null;
        //生成记录但不发送的记录
        MsgResult<Integer> preSendResult = emsYkYtIssueService.modifyYtDataByInit(requestVO,null,true,recordDetail.getClientIp());
        if(StatusType.OK.getCode() == preSendResult.getStatus()){
            msgId = preSendResult.getData();
            log.info("生成记录但不发送的遥控/遥调记录, 返回结果msgId: {}", msgId);
            recordDetail.setMsgId(msgId);
            recordDetail.setGmtModify(System.currentTimeMillis());
            emsControlRecordDetailDAO.updateById(recordDetail);
            //通过生成下发记录的id,进行下发
            MsgResult<Integer> msgResult = emsYkYtIssueService.modifyYtDataByInit(requestVO,msgId,false,recordDetail.getClientIp());
            if(StatusType.OK.getCode() != msgResult.getStatus()){
                log.error("生成记录但不发送的遥控/遥调记录执行再次下发操作失败, msgId: {}", msgId);
                recordDetail.setStatus(ControlRecordStatusEnum.FAIL.getCode());
                recordDetail.setGmtModify(System.currentTimeMillis());
                emsControlRecordDetailDAO.updateById(recordDetail);
                this.failRecord(record);
            }else {
                log.info("生成记录但不发送的遥控/遥调记录执行再次下发操作成功, msgId: {}", msgId);
            }
        }else {
            recordDetail.setStatus(ControlRecordStatusEnum.FAIL.getCode());
            recordDetail.setGmtModify(System.currentTimeMillis());
            emsControlRecordDetailDAO.updateById(recordDetail);
            this.failRecord(record);
        }
        //步骤详情的日志记录
        String log = String.format("群控群调->执行某条步骤完成,单条记录数据为：%s",JacksonUtil.toJSONString(recordDetail));
        emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(recordDetail.getRecordId()).content(log).gmtCreate(new Date()).build());
    }

    /**
     * 检查状态
     * @param recordDetail
     */
    public void checkRecordDetailStatus(EmsControlRecordDetail recordDetail) {
        log.info("checkRecordDetailStatus方法执行, id: {}, status: {}", recordDetail.getId(), recordDetail.getStatus());
        if (recordDetail.getStatus().equals(ControlRecordStatusEnum.SUCCESS.getCode())) {
            //成功
            Integer remoteType = recordDetail.getDitType().equals(DitTypeEnum.YK.getCode()) ? RemoteType.YK.getCode() : RemoteType.YT.getCode();
            //操作遥控遥调记录数据库表
            emsYkYtRecordDAO.deleteRecord(recordDetail.getDeviceCode(), remoteType, recordDetail.getDit());
            EmsYkYtRecord emsYkYtRecord = EmsYkYtRecord.builder()
                    .deviceCode(recordDetail.getDeviceCode())
                    .remoteType(remoteType)
                    .dit(recordDetail.getDit())
                    .value(Double.valueOf(recordDetail.getVal()))
                    .build();
            emsYkYtRecordDAO.save(emsYkYtRecord);
            this.hasNextStep(recordDetail);
        } else if (recordDetail.getStatus().equals(ControlRecordStatusEnum.FAIL.getCode())){
            //失败
            EmsControlRecord record = emsControlRecordDAO.getById(recordDetail.getRecordId());
            this.failRecord(record);
        }
    }

    /**
     * 是否有下一步
     * @param recordDetail
     */
    private void hasNextStep(EmsControlRecordDetail recordDetail) {
        EmsControlRecord record = emsControlRecordDAO.getById(recordDetail.getRecordId());
        EmsControlRecordDetail nextRecordDetail = emsControlRecordDetailDAO.selectByRecordIdAndStepId(recordDetail.getRecordId(), recordDetail.getStepNum());
        if (nextRecordDetail != null) {
            //有下个步骤，则继续执行
            log.info("有下一步骤, nextRecordDetail.id: {}", nextRecordDetail.getId());
            this.executeStep(nextRecordDetail);
        } else {
            //没有下个步骤了
            //当前流程执行完成
            log.info("没有下个步骤");
            this.finishRecord(record);
        }
    }

    private void finishRecord(EmsControlRecord record) {
        log.info("finishRecord执行, recordId: {}", record.getId());
        record.setStatus(ControlRecordStatusEnum.SUCCESS.getCode());
        record.setGmtModify(System.currentTimeMillis());
        emsControlRecordDAO.updateById(record);
        //群控群调执行完毕
        String log = String.format("群控群调->此次群控群调成功,主记录更新为：%s",JacksonUtil.toJSONString(record));
        emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(record.getId()).content(log).gmtCreate(new Date()).build());
    }

    private void failRecord(EmsControlRecord record) {
        log.info("failRecord执行, recordId: {}", record.getId());
        record.setStatus(ControlRecordStatusEnum.FAIL.getCode());
        record.setGmtModify(System.currentTimeMillis());
        emsControlRecordDAO.updateById(record);
        //群控群调失败不在执行
        String log = String.format("群控群调->此次群控群调失败,主记录更新为：%s",JacksonUtil.toJSONString(record));
        emsControlRecordLogDAO.save(EmsControlRecordLog.builder().recordId(record.getId()).content(log).gmtCreate(new Date()).build());
    }

    public MsgResult<Integer> modifyYtDataByInit(EmsIssueInitRequestVO requestVO,Integer msgId,Boolean preSend,String clientIp){
        //检查设备是否挂牌检修(检修则不下发)
        Integer listingType = extIotNodeDAO.selectByNodeId(requestVO.getDeviceCode()).getListingType();
        Assert.isTrue(!ListingTypeEnum.OVERHAUL.getCode().equals(listingType),"设备检修中");
        //执行下发操作,最多重试三次
        for (int i = 0; i < 3; i++) {
            try {
                if(RemoteType.YK.getCode().equals(requestVO.getRemoteType())){
                    MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yk(clientIp,msgId,requestVO.getInitDeviceCode(), requestVO.getRemoteDit(),requestVO.getVal().intValue(),preSend);
                    if(StatusType.OK.getCode() == result.getStatus()){
                        msgId = result.getData();
                        return MsgResult.<Integer>builder().status(StatusType.OK.getCode()).statusText(StatusType.OK.getStatusText()).data(msgId).build();
                    }
                }else if(RemoteType.YT.getCode().equals(requestVO.getRemoteType())){
                    MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yt(clientIp,msgId,requestVO.getInitDeviceCode(),requestVO.getRemoteDit(),requestVO.getVal(),preSend);
                    if(StatusType.OK.getCode() == result.getStatus()){
                        msgId = result.getData();
                        return MsgResult.<Integer>builder().status(StatusType.OK.getCode()).statusText(StatusType.OK.getStatusText()).data(msgId).build();
                    }
                }
            }catch (Exception e){
                log.error(String.format("遥控遥调下发操作%s次失败!",i+1));
            }
        }
        return MsgResult.<Integer>builder().status(StatusType.FAIL.getCode()).statusText(StatusType.FAIL.getStatusText()).build();
    }

    private void dealYkYtIssue(EmsDevice emsDevice,RemoteType remoteType,Double issueVal,String issueDit){
        //检查设备是否挂牌检修(检修则不下发)
        Integer listingType = extIotNodeDAO.selectByNodeId(emsDevice.getDeviceCode()).getListingType();
        Assert.isTrue(!ListingTypeEnum.OVERHAUL.getCode().equals(listingType),"设备检修中");
        if(RemoteType.YK == remoteType){
            //下发遥控
            MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yk(NetUtils.getClientIp(),null,emsDevice.getInitDeviceCode(), issueDit,issueVal.intValue(),false);
            if(StatusType.OK.getCode() != result.getStatus()){
                throw new CommonRuntimeException(StatusType.FAIL, result.getStatusText());
            }
        }else if(RemoteType.YT == remoteType){
            //下发遥调
            MsgResult<Integer> result = iFeignPowerNodeConsoleClient.yt(NetUtils.getClientIp(),null,emsDevice.getInitDeviceCode(),issueDit,issueVal,false);
            if(StatusType.OK.getCode() != result.getStatus()){
                throw new CommonRuntimeException(StatusType.FAIL, result.getStatusText());
            }
        }
        //操作遥控遥调记录数据库表
        emsYkYtRecordDAO.deleteRecord(emsDevice.getDeviceCode(), remoteType.getCode(), issueDit);
        EmsYkYtRecord emsYkYtRecord = EmsYkYtRecord.builder()
                .deviceCode(emsDevice.getDeviceCode())
                .remoteType(remoteType.getCode())
                .dit(issueDit)
                .value(issueVal)
                .build();
        emsYkYtRecordDAO.getBaseMapper().insert(emsYkYtRecord);
    }

    /**
     * 校验设备是否需要判断闭锁状态(点号可能来源其他设备)
     */
    private void validateDeviceLock(List<EmsDevice> emsDeviceList){
        List<EmsDeviceLock> deviceLockList = emsDeviceLockDAO.selectListByDeviceCodes(emsDeviceList.stream().map(d->d.getDeviceCode()).collect(Collectors.toList()));
        //如果这些设备没有闭锁配置,无需处理
        if(CollectionUtils.isEmpty(deviceLockList)){
            return;
        }
        //默认都为遥信点号
        List<QueryDataVO> queryDataVOList = deviceLockList.stream().map(d->
                QueryDataVO.builder()
                        .pid(d.getLockInitDeviceCode() + SysConstant.SPOT + d.getLockDit())
                        .initDeviceCode(d.getLockInitDeviceCode())
                        .deviceCode(d.getLockInitDeviceCode())
                        .dit(d.getLockDit())
                        .build()).collect(Collectors.toList());
        List<FlashDataVO> flashDataVOS = queryFlashDataCommonService.getFlashData(queryDataVOList);
        //实时数据map,value:实时值
        Map<String, String> flashDataMap = flashDataVOS.stream().collect(Collectors.toMap(FlashDataVO::getPid, FlashDataVO::getVal));
        //过滤那些处于闭锁状态的设备
        List<EmsDeviceLock> lockDeviceCodes = deviceLockList.stream().filter(d-> Objects.equals("1",flashDataMap.get(d.getLockInitDeviceCode() + SysConstant.SPOT + d.getLockDit()))).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(lockDeviceCodes)){
            return;
        }
        Map<String,String> deviceMap = emsDeviceList.stream().collect(Collectors.toMap(EmsDevice::getDeviceCode, EmsDevice::getDeviceName));
        throw new CommonRuntimeException(StatusType.FAIL,String.format("以下设备:%s,处于闭锁状态",
                lockDeviceCodes.stream().map(d-> deviceMap.get(d.getDeviceCode())).collect(Collectors.joining(","))));
    }
}
